#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>

#define SERVER_PORT 5432
#define MAX_PENDING 5
#define MAX_LINE 256

void *send_func(void *arg){ //send message
    int sockfd = (int)(long)arg;
    char send_buf[MAX_LINE];
    while(true){
        if(fgets(send_buf, MAX_LINE, stdin) == NULL){
            puts("no message\n");
            continue;
        }
        else{
            send(sockfd, send_buf, sizeof(send_buf), 0);
            printf("Server: %s\n", send_buf);
        }
        if (strncmp(send_buf, "quit", 4) == 0)break;
    }
    pthread_exit(0);
}

void *recv_func(void *arg){
    int sockfd = (int)(long)arg,recv_result;
    char recv_buf[MAX_LINE];
    while(true){
        recv_result = recv(sockfd, recv_buf, sizeof(recv_buf), 0);
        if (recv_result > 0)printf("Client: %s\n", recv_buf);
        if (strncmp(recv_buf, "quit", 4) == 0)break;
    }
    pthread_exit(0);
}

int main(){
    int s, new_s;
    pthread_t send_thread, recv_thread;
    struct sockaddr_in sin;
    socklen_t len = sizeof(sin);
    bzero((char*)&sin, sizeof(sin));              // fill every bite with 0
    sin.sin_family = AF_INET;                     // use IPv4 address
    sin.sin_addr.s_addr = INADDR_ANY;             // specific IP address
    sin.sin_port = htons(SERVER_PORT);            // port
    if((s = socket(PF_INET, SOCK_STREAM, 0)) < 0){      // create socket
        perror("simplex-talk: socket");
        exit(1);
    }
    if((bind(s, (struct sockaddr*)&sin, sizeof(sin))) < 0){
        perror("simplex-talk: bind");
        exit(1);
    }
    listen(s, MAX_PENDING);
    if((new_s = accept(s, (struct sockaddr*)&sin, &len)) < 0){
        perror("simplex-talk: accept");
        exit(1);
    }
    else{
        printf("Successfully connected!\n");
        printf("-----------------------------------\n");
    }
    int send_result, recv_result;
    send_result = pthread_create(&send_thread, NULL, send_func, (void*)(long)new_s);
    recv_result = pthread_create(&recv_thread, NULL, recv_func, (void*)(long)new_s);
    if (send_result != 0)printf("Send_thread create failure\n");
    if (recv_result != 0)printf("Recv_thread create failure\n");
    send_result = pthread_join(send_thread, NULL);
    recv_result = pthread_join(recv_thread, NULL);
    close(s);
    close(new_s);
    return 0;
}
